home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / DBUGDEMO.PAK / S_PAINT.C < prev    next >
C/C++ Source or Header  |  1997-05-06  |  15KB  |  466 lines

  1. /**********************************************************************
  2.  *          Copyright (c) 1993 by Borland International, Inc.         *
  3.  *                                                                    *
  4.  *                            S_PAINT.C                               *
  5.  *                                                                    *
  6.  *  This program demonstrates how to write a simple Windows graphics  *
  7.  *  program. It's called Simple Paint and provides three objects the  *
  8.  *  user can draw, a line, an ellipse, and a rectangle. Simple Paint  *
  9.  *  also provides the user with three choices of line thicknesses     *
  10.  *  and three choices of colors: red, green, and black.               *
  11.  **********************************************************************/
  12.  
  13. #define STRICT
  14.  
  15. #include <windows.h>
  16. #include "dbugdemo.h"
  17.  
  18. //   FUNCTION PROTOTYPES
  19.  
  20. int  DoWMCommand(WPARAM wParam, HWND hWnd);
  21. void DoLButtonDown(HWND hWnd, LONG lParam);
  22. void DoLButtonUp(HWND hWnd, LONG lParam);
  23. void DoMouseMove(HWND hWnd, LONG lParam);
  24. void DoPaint(HWND hWnd);
  25. void DrawShape(HDC hdc, int x, int y, int x2, int y2, int Shape,
  26.                int PenWidth, COLORREF PenColor, int Slope);
  27. LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
  28.  
  29. //   GLOBAL VARIABLES
  30.  
  31. #define ShapeI 100
  32.  
  33. int ShapeNumber = -1;           // Indicates the number of shapes drawn.
  34.  
  35. int CurrentShape = LINE;        // The shape the user is drawing.
  36.  
  37. int PenWidth = 3;               // The current pen width.
  38.                                 // Default width is medium.
  39.  
  40. COLORREF PenColor = RGB(255, 0, 0);    // The current pen color.
  41.                                        // Default is red.
  42.  
  43. typedef struct SSHAPE           // Struct which tracks the drawn shapes.
  44. {
  45.         RECT       Points;      // Location of shape.
  46.         int        PenWidth;    // Pen width for the shape.
  47.         int        Shape;       // Type of shape.
  48.         COLORREF   PenColor;    // Color of shape.
  49.         int        Slope;       // Used to draw lines correctly.
  50. } SHAPE;
  51.  
  52. SHAPE Shapes[ShapeI];           // Array that stores the shapes.
  53.  
  54. /*******************************************************
  55.  * function WinMain
  56.  *******************************************************/
  57. #pragma argsused
  58. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  59.                    LPSTR lpszCmdLine, int nCmdShow)
  60. {
  61.     WNDCLASS    wndClass;
  62.     MSG         msg;
  63.     HWND        hWnd;
  64.  
  65.     /*
  66.      * Register window class style if first
  67.      * instance of this program.
  68.      */
  69.     if (!hPrevInstance)
  70.     {
  71.         wndClass.style          = CS_HREDRAW | CS_VREDRAW;
  72.         wndClass.lpfnWndProc    = WndProc;
  73.         wndClass.cbClsExtra     = 0;
  74.         wndClass.cbWndExtra     = 0;
  75.         wndClass.hInstance      = hInstance;
  76.         wndClass.hIcon          = LoadIcon(hInstance, "IDI_SIMPLEPAINT");
  77.         wndClass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  78.         wndClass.hbrBackground  = GetStockObject(WHITE_BRUSH);
  79.         wndClass.lpszMenuName   = szAppName;
  80.         wndClass.lpszClassName  = szAppName;
  81.  
  82.         if (!RegisterClass(&wndClass))
  83.             return FALSE;
  84.     }
  85.  
  86.     /*
  87.      * Create and display the window.
  88.      */
  89.     hWnd = CreateWindow(szAppName, "Simple Paint",
  90.                WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,0,
  91.                CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
  92.  
  93.     ShowWindow(hWnd, nCmdShow);
  94.     UpdateWindow(hWnd);
  95.  
  96.     while (GetMessage(&msg, NULL, 0, 0))
  97.     {
  98.         TranslateMessage(&msg);
  99.         DispatchMessage(&msg);
  100.     }
  101.     return 0;
  102. }
  103.  
  104. /*******************************************************
  105.  * function WndProc
  106.  *    Handles all messages received by the window
  107.  *******************************************************/
  108. LRESULT CALLBACK WndProc (HWND hWnd, UINT Message,
  109.                           WPARAM wParam, LPARAM lParam)
  110. {
  111.     switch(Message)
  112.     {
  113.         case WM_COMMAND:
  114.             return DoWMCommand(wParam, hWnd);
  115.  
  116.         case WM_LBUTTONDOWN:
  117.             DoLButtonDown(hWnd, lParam);
  118.             break;
  119.  
  120.         case WM_LBUTTONUP:
  121.             DoLButtonUp(hWnd, lParam);
  122.             break;
  123.  
  124.         case WM_MOUSEMOVE:
  125.             DoMouseMove(hWnd, lParam);
  126.             break;
  127.  
  128.         case WM_PAINT:
  129.             DoPaint(hWnd);
  130.             break;
  131.  
  132.         case WM_DESTROY:
  133.             PostQuitMessage(0);
  134.             break;
  135.  
  136.         default:
  137.             return DefWindowProc(hWnd, Message, wParam, lParam);
  138.     }
  139.     return 0;
  140. }
  141.  
  142. /*****************************************************************
  143.  * function DrawShape
  144.  *    Draws the shape given by Shape parameter using PenWidth
  145.  *    and PenColor in the rectangle bounded by x,y,x2,y2. The
  146.  *    Slope parameter is used with LINE shapes to determine if
  147.  *    lines should be drawn with a negative or positive slope.
  148.  *****************************************************************/
  149. #pragma argsused
  150. void DrawShape(HDC hdc, int x, int y, int x2, int y2, int Shape,
  151.                int PenWidth, COLORREF PenColor, int Slope)
  152. {
  153.     HANDLE      saveObject;
  154.  
  155.     /*
  156.      * Create the proper pen for this shape. Save the
  157.      * previously selected object from this DC.
  158.      */
  159.     saveObject = SelectObject(hdc, CreatePen(PS_SOLID,
  160.                               PenWidth, PenColor));
  161.     switch(Shape)
  162.     {
  163.         case LINE:
  164.             /* If Slope is set, then draw from LowerRight to UpperLeft. If
  165.              * Slope is not set then draw from UpperLeft to LowerRight.
  166.              */
  167.             if (Slope == 1)
  168.             {
  169.                 MoveToEx(hdc, x, y2, NULL);
  170.                 LineTo(hdc, x2, y);
  171.             }
  172.             else 
  173.             {
  174.                 MoveToEx(hdc, x, y, NULL);
  175.                 LineTo(hdc, x2, y2);
  176.             }
  177.             break;
  178.  
  179.         case ELLIPSE:
  180.             Ellipse(hdc, x, y, x2, y2);
  181.             break;
  182.  
  183.         case RECTANGLE:
  184.             Rectangle(hdc, x, y, x2, y2);
  185.             break;
  186.     }
  187.  
  188.     /*
  189.      * Delete the currently selected object (the pen) and select whatever
  190.      * object was selected when we entered this routine.
  191.      */
  192.  
  193.     DeleteObject(SelectObject(hdc, saveObject));
  194. }
  195.  
  196. /****************************************************************
  197.  * function DoPaint
  198.  *    Processes WM_PAINT messages. WM_PAINT is generated
  199.  *    whenever UpdateWindow is called or another window is moved,
  200.  *    revealing a portion of the window receiving this message.
  201.  ****************************************************************/
  202. void DoPaint(HWND hWnd)
  203. {
  204.     int           i;
  205.     HDC           hdc, hMemDC;
  206.     RECT          theRect, destRect;
  207.     HBITMAP       theBitmap;
  208.     PAINTSTRUCT   ps;
  209.  
  210.     hdc = BeginPaint(hWnd, &ps);
  211.  
  212.     if (ShapeNumber >= 0)
  213.     {
  214.         /*
  215.          * Determine which rectangle on the window is invalid.
  216.          * If no rectangle is marked invalid, it will be a full
  217.          * window repaint.
  218.          */
  219.         GetUpdateRect(hWnd, &theRect, 0);
  220.         if (IsRectEmpty(&theRect))
  221.             GetClientRect(hWnd, &theRect);
  222.  
  223.         /*
  224.          * Create a memory DC and bitmap the same
  225.          * size as the update rectangle.
  226.          */
  227.         hMemDC = CreateCompatibleDC(hdc);
  228.         theBitmap = CreateCompatibleBitmap(hdc,
  229.                          theRect.right-theRect.left,
  230.                          theRect.bottom-theRect.top);
  231.         SelectObject(hMemDC, theBitmap);
  232.  
  233.         /*
  234.          * Erase the memBitmap.
  235.          */
  236.         BitBlt(hMemDC, 0, 0,
  237.                theRect.right-theRect.left,
  238.                theRect.bottom-theRect.top,
  239.                hdc, 0, 0, SRCCOPY);
  240.  
  241.         /*
  242.          * Draw only those shapes that lie
  243.          * within the update rectangle.
  244.          */
  245.         for (i = 0; i <= ShapeNumber; ++i)
  246.         {
  247.             IntersectRect(&destRect, &Shapes[i].Points, &theRect);
  248.             if (!IsRectEmpty(&destRect))
  249.                 DrawShape(hMemDC,
  250.                     Shapes[i].Points.left-theRect.left,
  251.                     Shapes[i].Points.top-theRect.top,
  252.                     Shapes[i].Points.right-theRect.left,
  253.                     Shapes[i].Points.bottom-theRect.top,
  254.                     Shapes[i].Shape,
  255.                     Shapes[i].PenWidth,
  256.                     Shapes[i].PenColor,
  257.                     Shapes[i].Slope);
  258.             /*
  259.              * Note that when drawing the shape, the shape's
  260.              * position was transformed so that the origin was
  261.              * at the upper-left corner of the update rectangle.
  262.              * This is the point (0,0) on the bitmap that will
  263.              * map onto (theRect.left,theRect.top).
  264.              */
  265.         }
  266.  
  267.         /*
  268.          * Finally, copy the bitmap onto the update rectangle.
  269.          */
  270.         BitBlt(hdc, theRect.left, theRect.top,
  271.                theRect.right-theRect.left,
  272.                theRect.bottom-theRect.top,
  273.                hMemDC, 0, 0, SRCCOPY);
  274.  
  275.         DeleteDC(hMemDC);
  276.         DeleteObject(theBitmap);
  277.     }
  278.     EndPaint(hWnd, &ps);
  279. }
  280.  
  281. /**********************************************************
  282.  * static variables oldx, oldy, mouseDown
  283.  *    Used to maintain both the state of the mouse position
  284.  *    and the button status between mouse messages.
  285.  **********************************************************/
  286.  
  287. static  oldx = -1, oldy = -1, mouseDown = 0;
  288.  
  289. /******************************************************************
  290.  * function DoLButtonDown
  291.  *    When the left button on the mouse is pressed, this routine
  292.  *    saves the origin of this shape, the current pen parameters,
  293.  *    and the current shape into the shapes array. The mouse
  294.  *    button is also marked as pressed.
  295.  ******************************************************************/
  296. void DoLButtonDown(HWND hWnd, LONG lParam)
  297. {
  298.     /*
  299.      * Redirect all subsequent mouse movements to this
  300.      * window until the mouse button is released.
  301.      */
  302.     SetCapture(hWnd);
  303.     oldy = Shapes[++ShapeNumber].Points.top = HIWORD(lParam);
  304.     oldx = Shapes[ShapeNumber].Points.left = LOWORD(lParam);
  305.     Shapes[ShapeNumber].Shape = CurrentShape;
  306.     Shapes[ShapeNumber].PenWidth = PenWidth;
  307.     Shapes[ShapeNumber].PenColor = PenColor;
  308.  
  309.     mouseDown = 1;
  310. }
  311.  
  312. /******************************************************************
  313.  * function DoLButtonUp
  314.  *    When the Left mouse button is released, this routine
  315.  *    allows other windows to receive mouse messages and saves
  316.  *    the position of the mouse as the other corner of a bounding
  317.  *    rectangle for the shape.
  318.  ******************************************************************/
  319. void DoLButtonUp(HWND hWnd, LONG lParam)
  320. {
  321.     if (mouseDown == 0)
  322.         return;
  323.  
  324.     ReleaseCapture();
  325.  
  326.     /*
  327.      * For rectangles to work with the IntersectRect function,
  328.      * they must be stored as left, top, right, bottom.
  329.      */
  330.  
  331.     SetRect(&Shapes[ShapeNumber].Points,
  332.         min(Shapes[ShapeNumber].Points.left, LOWORD(lParam)),
  333.         min(Shapes[ShapeNumber].Points.top, HIWORD(lParam)),
  334.         max(Shapes[ShapeNumber].Points.left, LOWORD(lParam)),
  335.         max(Shapes[ShapeNumber].Points.top, HIWORD(lParam)));
  336.  
  337.     /*
  338.      * If slope is decreasing, set equal to 0, then draw from UpperLeft
  339.      * to LowerRight. If slope is increasing, set equal to 1, and draw
  340.      * draw from LowerLeft to UpperRight.
  341.      */
  342.  
  343.     if (CurrentShape == LINE)
  344.         Shapes[ShapeNumber].Slope = ((Shapes[ShapeNumber].Points.left ==
  345.             LOWORD(lParam)) ^ (Shapes[ShapeNumber].Points.top ==
  346.             HIWORD(lParam))) ?  1 : 0;
  347.  
  348.         /*
  349.          * This statement uses an exclusive-or because the following
  350.          * is true for a line drawn from LowerRight to UpperLeft:
  351.          *     ((Shapes[ShapeNumber].Points.left == LOWORD) &&
  352.          *         (Shapes[ShapeNumber].Points.right == HIWORD)).
  353.          */
  354.  
  355.     /*
  356.      * Mark this region on the window as needing redrawing and force an 
  357.      * update.
  358.      */
  359.  
  360.     InvalidateRect(hWnd, &Shapes[ShapeNumber].Points, 0);
  361.     UpdateWindow(hWnd);
  362.     mouseDown = 0;
  363.     oldx = -1;
  364.     oldy = -1;
  365. }
  366.  
  367. static int SaveROP;
  368.  
  369. /**********************************************************************
  370.  * function DoMouseMove
  371.  *    When the mouse is moved and the button is down, this function
  372.  *    draws the current shape. It uses the Raster Operation NOTXORPEN
  373.  *    to draw the shape. When this mode is used, drawing the
  374.  *    same image twice returns the image to its original state.
  375.  *    NOTXORPEN turns black on black white, black on white black
  376.  *    and white on white white.
  377.  **********************************************************************/
  378. void DoMouseMove(HWND hWnd, LONG lParam)
  379. {
  380.     HDC hdc;
  381.  
  382.     if (mouseDown)
  383.     {
  384.         hdc = GetDC(hWnd);
  385.         /*
  386.          * Erase the old shape as the mouse is moved.
  387.          */
  388.         SaveROP = SetROP2(hdc, R2_NOTXORPEN);
  389.         DrawShape(hdc, Shapes[ShapeNumber].Points.left,
  390.                   Shapes[ShapeNumber].Points.top, oldx, oldy,
  391.                   Shapes[ShapeNumber].Shape,
  392.                   Shapes[ShapeNumber].PenWidth,
  393.                   Shapes[ShapeNumber].PenColor,
  394.                   0);
  395.         /*
  396.          * Draw the new shape to the new mouse position.
  397.          */
  398.         oldx = LOWORD(lParam);
  399.         oldy = HIWORD(lParam);
  400.         DrawShape(hdc, Shapes[ShapeNumber].Points.left,
  401.                   Shapes[ShapeNumber].Points.top, oldx, oldy,
  402.                   Shapes[ShapeNumber].Shape,
  403.                   Shapes[ShapeNumber].PenWidth,
  404.                   Shapes[ShapeNumber].PenColor,
  405.                   0);
  406.         SetROP2(hdc, SaveROP);
  407.         ReleaseDC(hWnd, hdc);
  408.     }
  409. }
  410.  
  411. /*********************************************************************
  412.  * function DoWMCommand
  413.  *    When a menu item is selected, this function changes the current
  414.  *    state of shape selections to match the user's menu selection.
  415.  *******************************************************************/
  416. int DoWMCommand(WPARAM wParam, HWND hWnd)
  417. {
  418.     switch(wParam)
  419.     {
  420.         case MID_QUIT:
  421.             DestroyWindow(hWnd);
  422.             break;
  423.  
  424.         case MID_LINE:
  425.             CurrentShape = LINE;
  426.             break;
  427.  
  428.         case MID_ELLIPSE:
  429.             CurrentShape = ELLIPSE;
  430.             break;
  431.  
  432.         case MID_RECTANGLE:
  433.             CurrentShape = RECTANGLE;
  434.             break;
  435.  
  436.         case MID_THIN:
  437.             PenWidth = 1;
  438.             break;
  439.  
  440.         case MID_REGULAR:
  441.             PenWidth = 3;
  442.             break;
  443.  
  444.         case MID_THICK:
  445.             PenWidth = 5;
  446.             break;
  447.  
  448.         case MID_RED:
  449.             PenColor = RGB(255, 0, 0);
  450.             break;
  451.  
  452.         case MID_GREEN:
  453.             PenColor = RGB(0, 255, 0);
  454.             break;
  455.  
  456.         case MID_BLACK:
  457.             PenColor = RGB(0, 0, 0);
  458.             break;
  459.  
  460.         default:
  461.             return 0;
  462.     }
  463.     return 1;
  464. }
  465.  
  466.